﻿using System;

namespace EnterpriseLibraryExtensions.Events
{
    /// <summary>
    /// Deriving from the HandlesEvent class is an easy way to implement the IHandlesEvent interface in a type safe manner.
    /// </summary>
    /// <typeparam name="TEventType">The type of event that the derived event handler handles.</typeparam>
    public abstract class HandlesEvent<TEventType> : IHandlesEvent<TEventType>
    {
        /// <summary>
        /// Initializes a new instance of the HandlesEvent class and marks it for synchronous execution.
        /// </summary>
        protected HandlesEvent()
            : this(false)
        {
        }

        /// <summary>
        /// Initializes a new instance of the HandlesEvent class and makes it possible to specify asynchronous execution.
        /// </summary>
        /// <param name="executeAsync">Specifies if the derived event handler class can run asynchroniously.</param>
        protected HandlesEvent(bool executeAsync)
        {
            ExecuteAsync = executeAsync;
        }

        /// <summary>
        /// Gets the type of event supported by the derived class.
        /// </summary>
        public Type EventType
        {
            get { return typeof(TEventType); }
        }

        /// <summary>
        /// Gets a value indicating whether the event handler can run asynchronous.
        /// </summary>
        public bool ExecuteAsync { get; private set; }

        /// <summary>
        /// This method is called by the eventing framework when the event type supported by the event handler is raised.
        /// </summary>
        /// <param name="sender">The instance raising the event. The value can be null.</param>
        /// <param name="args">The arguments of type TEventType. Value cannot be null.</param>
        public void OnEvent(object sender, object args)
        {
            if (args == null)
            {
                throw new ArgumentNullException("args");
            }

            EventsTracer.TraceInformation("Responding to event. Sender: {0}, Arguments: {1}", sender, args);

            Handle(sender, new EventArgs<TEventType>((TEventType)args));

            EventsTracer.TraceInformation("Event handled.");
        }

        /// <summary>
        /// The Handle method implements the actual event handling in the derived classes.
        /// </summary>
        /// <param name="sender">The instance raising the event. Value can be null.</param>
        /// <param name="args">The arguments of the event. Value will not be null.</param>
        protected abstract void Handle(object sender, EventArgs<TEventType> args);
    }
}
